Generic_tech#

gdsfactory includes a generic Technology module in gdsfactory.generic_tech that you can use as an inspiration to create your own.

LayerMap#

A layer map maps layer names to a integer numbers pair (GDSlayer, GDSpurpose)

Each foundry uses different GDS layer numbers for different process steps.

We follow the generic layer numbers from the book “Silicon Photonics Design: From Devices to Systems Lukas Chrostowski, Michael Hochberg”.

GDS (layer, purpose)

layer_name

Description

1 , 0

WG

220 nm Silicon core

2 , 0

SLAB150

150nm Silicon slab (70nm shallow Etch for grating couplers)

3 , 0

SLAB90

90nm Silicon slab (for modulators)

4, 0

DEEPTRENCH

Deep trench

47, 0

MH

heater

41, 0

M1

metal 1

45, 0

M2

metal 2

40, 0

VIAC

VIAC to contact Ge, NPP or PPP

44, 0

VIA1

VIA1

46, 0

PADOPEN

Bond pad opening

51, 0

UNDERCUT

Undercut

66, 0

TEXT

Text markup

64, 0

FLOORPLAN

Mask floorplan

[1]:
from pydantic import BaseModel
from typing import Tuple

import gdsfactory as gf
from gdsfactory.generic_tech import LAYER, LAYER_STACK
from gdsfactory.generic_tech.get_klayout_pyxs import get_klayout_pyxs
from gdsfactory.technology import LayerLevel, LayerStack
2023-02-20 17:45:58.015 | INFO     | gdsfactory.config:<module>:50 - Load '/home/runner/work/gdsfactory/gdsfactory/gdsfactory' 6.43.1
[2]:
Layer = Tuple[int, int]

gf.config.rich_output()
PDK = gf.get_generic_pdk()
PDK.activate()


class GenericLayerMap(BaseModel):
    """Generic layermap based on book.

    Lukas Chrostowski, Michael Hochberg, "Silicon Photonics Design",
    Cambridge University Press 2015, page 353
    You will need to create a new LayerMap with your specific foundry layers.
    """

    WAFER: Layer = (99999, 0)

    WG: Layer = (1, 0)
    WGCLAD: Layer = (111, 0)
    SLAB150: Layer = (2, 0)
    SLAB90: Layer = (3, 0)
    DEEPTRENCH: Layer = (4, 0)
    GE: Layer = (5, 0)
    UNDERCUT: Layer = (6, 0)
    WGN: Layer = (34, 0)
    WGN_CLAD: Layer = (36, 0)

    N: Layer = (20, 0)
    NP: Layer = (22, 0)
    NPP: Layer = (24, 0)
    P: Layer = (21, 0)
    PP: Layer = (23, 0)
    PPP: Layer = (25, 0)
    GEN: Layer = (26, 0)
    GEP: Layer = (27, 0)

    HEATER: Layer = (47, 0)
    M1: Layer = (41, 0)
    M2: Layer = (45, 0)
    M3: Layer = (49, 0)
    VIAC: Layer = (40, 0)
    VIA1: Layer = (44, 0)
    VIA2: Layer = (43, 0)
    PADOPEN: Layer = (46, 0)

    DICING: Layer = (100, 0)
    NO_TILE_SI: Layer = (71, 0)
    PADDING: Layer = (67, 0)
    DEVREC: Layer = (68, 0)
    FLOORPLAN: Layer = (64, 0)
    TEXT: Layer = (66, 0)
    PORT: Layer = (1, 10)
    PORTE: Layer = (1, 11)
    PORTH: Layer = (70, 0)
    SHOW_PORTS: Layer = (1, 12)
    LABEL: Layer = (201, 0)
    LABEL_SETTINGS: Layer = (202, 0)
    TE: Layer = (203, 0)
    TM: Layer = (204, 0)
    DRC_MARKER: Layer = (205, 0)
    LABEL_INSTANCE: Layer = (206, 0)
    ERROR_MARKER: Layer = (207, 0)
    ERROR_PATH: Layer = (208, 0)

    SOURCE: Layer = (110, 0)
    MONITOR: Layer = (101, 0)

    class Config:
        """pydantic config."""

        frozen = True
        extra = "forbid"


LAYER = GenericLayerMap()
LAYER
2023-02-20 17:45:58.928 | INFO     | gdsfactory.technology.layer_views:__init__:785 - Importing LayerViews from YAML file: /home/runner/work/gdsfactory/gdsfactory/gdsfactory/generic_tech/layer_views.yaml.
2023-02-20 17:45:58.935 | INFO     | gdsfactory.pdk:activate:206 - 'generic' PDK is now active
GenericLayerMap(
    WAFER=(99999, 0),
    WG=(1, 0),
    WGCLAD=(111, 0),
    SLAB150=(2, 0),
    SLAB90=(3, 0),
    DEEPTRENCH=(4, 0),
    GE=(5, 0),
    UNDERCUT=(6, 0),
    WGN=(34, 0),
    WGN_CLAD=(36, 0),
    N=(20, 0),
    NP=(22, 0),
    NPP=(24, 0),
    P=(21, 0),
    PP=(23, 0),
    PPP=(25, 0),
    GEN=(26, 0),
    GEP=(27, 0),
    HEATER=(47, 0),
    M1=(41, 0),
    M2=(45, 0),
    M3=(49, 0),
    VIAC=(40, 0),
    VIA1=(44, 0),
    VIA2=(43, 0),
    PADOPEN=(46, 0),
    DICING=(100, 0),
    NO_TILE_SI=(71, 0),
    PADDING=(67, 0),
    DEVREC=(68, 0),
    FLOORPLAN=(64, 0),
    TEXT=(66, 0),
    PORT=(1, 10),
    PORTE=(1, 11),
    PORTH=(70, 0),
    SHOW_PORTS=(1, 12),
    LABEL=(201, 0),
    LABEL_SETTINGS=(202, 0),
    TE=(203, 0),
    TM=(204, 0),
    DRC_MARKER=(205, 0),
    LABEL_INSTANCE=(206, 0),
    ERROR_MARKER=(207, 0),
    ERROR_PATH=(208, 0),
    SOURCE=(110, 0),
    MONITOR=(101, 0)
)
[3]:
layer_wg = gf.LAYER.WG
print(layer_wg)
(1, 0)

Extract layers#

You can also extract layers using the extract function. This function returns a new flattened Component that contains the extracted layers. A flat Component does not have references, and all the polygons are absorbed into the top cell.

[4]:
from gdsfactory.generic_tech import get_generic_pdk

PDK = get_generic_pdk()
PDK.activate()

LAYER_VIEWS = PDK.layer_views
c = LAYER_VIEWS.preview_layerset()
c
2023-02-20 17:45:59.078 | INFO     | gdsfactory.technology.layer_views:__init__:785 - Importing LayerViews from YAML file: /home/runner/work/gdsfactory/gdsfactory/gdsfactory/generic_tech/layer_views.yaml.
2023-02-20 17:45:59.085 | INFO     | gdsfactory.pdk:activate:206 - 'generic' PDK is now active
layerset_eeb63ddc: uid eeb63ddc, ports [], references ['rectangle_1', 'text_1', 'rectangle_2', 'text_2', 'rectangle_3', 'text_3', 'rectangle_4', 'text_4', 'rectangle_5', 'text_5', 'rectangle_6', 'text_6', 'rectangle_7', 'text_7', 'rectangle_8', 'text_8', 'rectangle_9', 'text_9', 'rectangle_10', 'text_10', 'rectangle_11', 'text_11', 'rectangle_12', 'text_12', 'rectangle_13', 'text_13', 'rectangle_14', 'text_14', 'rectangle_15', 'text_15', 'rectangle_16', 'text_16', 'rectangle_17', 'text_17', 'rectangle_18', 'text_18', 'rectangle_19', 'text_19', 'rectangle_20', 'text_20', 'rectangle_21', 'text_21', 'rectangle_22', 'text_22', 'rectangle_23', 'text_23', 'rectangle_24', 'text_24', 'rectangle_25', 'text_25', 'rectangle_26', 'text_26', 'rectangle_27', 'text_27', 'rectangle_28', 'text_28', 'rectangle_29', 'text_29', 'rectangle_30', 'text_30', 'rectangle_31', 'text_31', 'rectangle_32', 'text_32', 'rectangle_33', 'text_33', 'rectangle_34', 'text_34', 'rectangle_35', 'text_35', 'rectangle_36', 'text_36', 'rectangle_37', 'text_37', 'rectangle_38', 'text_38', 'rectangle_39', 'text_39', 'rectangle_40', 'text_40', 'rectangle_41', 'text_41', 'rectangle_42', 'text_42', 'rectangle_43', 'text_43', 'rectangle_44', 'text_44', 'rectangle_45', 'text_45', 'rectangle_46', 'text_46', 'rectangle_47', 'text_47', 'rectangle_48', 'text_48', 'rectangle_49', 'text_49', 'rectangle_50', 'text_50', 'rectangle_51', 'text_51', 'rectangle_52', 'text_52', 'rectangle_53', 'text_53', 'rectangle_54', 'text_54', 'rectangle_55', 'text_55', 'rectangle_56', 'text_56', 'rectangle_57', 'text_57', 'rectangle_58', 'text_58', 'rectangle_59', 'text_59', 'rectangle_60', 'text_60', 'rectangle_61', 'text_61', 'rectangle_62', 'text_62', 'rectangle_63', 'text_63', 'rectangle_64', 'text_64', 'rectangle_65', 'text_65', 'rectangle_66', 'text_66', 'rectangle_67', 'text_67', 'rectangle_68', 'text_68', 'rectangle_69', 'text_69', 'rectangle_70', 'text_70', 'rectangle_71', 'text_71', 'rectangle_72', 'text_72', 'rectangle_73', 'text_73', 'rectangle_74', 'text_74', 'rectangle_75', 'text_75', 'rectangle_76', 'text_76', 'rectangle_77', 'text_77', 'rectangle_78', 'text_78', 'rectangle_79', 'text_79', 'rectangle_80', 'text_80', 'rectangle_81', 'text_81', 'rectangle_82', 'text_82'], 0 polygons
[5]:
extract = c.extract(layers=(gf.LAYER.M1, gf.LAYER.VIAC))
extract
/home/runner/work/gdsfactory/gdsfactory/gdsfactory/component.py:1684: UserWarning: Component 'Unnamed_500dd4c5' contains 1 Unnamed cells
  warnings.warn(
Unnamed_500dd4c5: uid 500dd4c5, ports [], references [], 19 polygons

Remove layers#

You can remove layers using the remove_layers() function.

[6]:
removed = extract.remove_layers(layers=(gf.LAYER.VIAC,))
removed
Unnamed_500dd4c5: uid 500dd4c5, ports [], references [], 8 polygons

Remap layers#

You can remap (change the polygons from one layer to another layer) using the remap_layer, which will return a new Component

[7]:
c = gf.components.straight(layer=(2, 0))
c
straight_layer2__0: uid 6e350b84, ports ['o1', 'o2'], references [], 1 polygons
[8]:
remap = c.remap_layers(layermap={(2, 0): gf.LAYER.WGN})
remap
/home/runner/work/gdsfactory/gdsfactory/gdsfactory/component.py:1684: UserWarning: Component 'Unnamed_51adbcde' contains 1 Unnamed cells
  warnings.warn(
Unnamed_51adbcde: uid 51adbcde, ports ['o1', 'o2'], references [], 1 polygons

LayerViews#

Klayout shows each GDS layer with a color, style and transparency

You can define your layerViews in a klayout Layer Properties file layers.lyp or in YAML format

We recommend using YAML and then generate the lyp in klayout, as YAML is easier to modify than XML.


[9]:
from IPython.display import Code
from gdsfactory.config import PATH

Code(filename=PATH.klayout_yaml)
[9]:
LayerViews:
  Waveguide:
    layer: [1, 0]
    hatch_pattern: dotted
    width: 1
    color: "#ff9d9d"
  WGCLAD:
    layer: [111, 0]
    layer_in_name: true
    hatch_pattern: coarsely dotted
    visible: false
    width: 1
    color: "silver"
  SLAB150:
    layer: [2, 0]
    layer_in_name: true
    hatch_pattern: coarsely dotted
    transparent: true
    width: 1
    color: "cyan"
  SLAB90:
    layer: [3, 0]
    layer_in_name: true
    hatch_pattern: hollow
    transparent: true
    width: 1
    color: "#805000"
  SHALLOWETCH:
    layer: [2, 6]
    layer_in_name: true
    hatch_pattern: coarsely dotted
    color: "blue"
  DEEPETCH:
    layer: [3, 6]
    layer_in_name: true
    hatch_pattern: coarsely dotted
    color: "#cc0000"
  SLAB150CLAD:
    layer: [2, 9]
    layer_in_name: true
    frame_color: "#9999cc"
    fill_color: "#80a8ff"
    hatch_pattern: coarsely dotted
    visible: false
    width: 1
  SLAB90CLAD:
    layer: [3, 1]
    layer_in_name: true
    frame_color: "#9999cc"
    fill_color: "#80a8ff"
    hatch_pattern: hollow
    visible: false
    width: 1
  Doping:
    group_members:
      N:
        layer: [20, 0]
        layer_in_name: true
        hatch_pattern: lightly left-hatched
        width: 1
        color: "red"
      NP:
        layer: [22, 0]
        layer_in_name: true
        hatch_pattern: lightly left-hatched
        width: 1
        color: "red"
      NPP:
        layer: [24, 0]
        layer_in_name: true
        hatch_pattern: coarsely dotted
        width: 1
        color: "red"
      P_210:
        layer: [21, 0]
        hatch_pattern: lightly left-hatched
        transparent: true
        width: 1
        color: "blue"
      PP:
        layer: [23, 0]
        layer_in_name: true
        hatch_pattern: lightly left-hatched
        width: 1
        color: "blue"
      PPP:
        layer: [25, 0]
        layer_in_name: true
        hatch_pattern: strongly left-hatched dense
        width: 1
        color: "blue"
      PDPP:
        layer: [27, 0]
        layer_in_name: true
        hatch_pattern: lightly cross-hatched
        width: 1
        color: "#ccb27f"
      GENPP:
        layer: [26, 0]
        layer_in_name: true
        hatch_pattern: plus
        width: 1
        color: "#cc00cc"
      GEPPP:
        layer: [29, 0]
        layer_in_name: true
        hatch_pattern: plus
        width: 1
        color: "#cc00cc"
  WGN_Nitride:
    layer: [34, 0]
    layer_in_name: true
    hatch_pattern: left-hatched
    transparent: true
    width: 1
    color: "#ff8000"
  WGNCLAD:
    layer: [36, 0]
    layer_in_name: true
    hatch_pattern: coarsely dotted
    visible: false
    width: 1
    color: "silver"
  GE:
    layer: [5, 0]
    layer_in_name: true
    hatch_pattern: dotted
    width: 1
    color: "magenta"
  SILICIDE:
    layer: [39, 0]
    layer_in_name: true
    hatch_pattern: strongly right-hatched sparse
    width: 1
    color: "#cc4c00"
  MH:
    layer: [47, 0]
    layer_in_name: true
    hatch_pattern: hollow
    transparent: true
    width: 1
    color: "#ff8000"
  M1:
    layer: [41, 0]
    layer_in_name: true
    hatch_pattern: hollow
    width: 1
    color: "#01ff6b"
    brightness: -16
  M2:
    layer: [45, 0]
    layer_in_name: true
    hatch_pattern: hollow
    width: 1
    color: "#008050"
  M3:
    layer: [49, 0]
    layer_in_name: true
    frame_color: "teal"
    fill_color: "#800057"
    hatch_pattern: hollow
  VIAC:
    layer: [40, 0]
    layer_in_name: true
    hatch_pattern: hollow
    width: 1
    color: "#cc4c00"
  VIA1:
    layer: [44, 0]
    layer_in_name: true
    hatch_pattern: hollow
    width: 1
    color: "grey"
  VIA2:
    layer: [43, 0]
    layer_in_name: true
    hatch_pattern: hollow
    width: 1
    color: "#805000"
  CAPACITOR:
    layer: [42, 0]
    layer_in_name: true
    hatch_pattern: dotted
    width: 1
    color: "#805000"
  METALOPEN:
    layer: [46, 0]
    layer_in_name: true
    hatch_pattern: cross-hatched
    width: 1
    color: "#606060"
  DEEPTRENCH:
    layer: [4, 0]
    layer_in_name: true
    hatch_pattern: lightly right-hatched
    width: 1
    color: "#9999cc"
  OXIDE_ETCH:
    layer: [6, 0]
    layer_in_name: true
    hatch_pattern: strongly left-hatched dense
    width: 1
    color: "black"
  SITILES:
    layer: [190, 0]
    layer_in_name: true
    hatch_pattern: coarsely dotted
    width: 1
    color: "black"
  M1TILES:
    layer: [191, 0]
    layer_in_name: true
    hatch_pattern: coarsely dotted
    width: 1
    color: "#91ff00"
  LABEL_OPTICAL_IO:
    layer: [201, 0]
    layer_in_name: true
    hatch_pattern: hollow
    width: 1
    color: "blue"
  LABEL_SETTINGS:
    layer: [202, 0]
    layer_in_name: true
    hatch_pattern: hollow
    visible: false
    width: 1
    color: "magenta"
  TE:
    layer: [203, 0]
    layer_in_name: true
    transparent: true
    width: 1
    color: "blue"
  TM:
    layer: [204, 0]
    layer_in_name: true
    width: 1
    color: "red"
  LABEL_INSTANCES:
    layer: [206, 0]
    layer_in_name: true
    hatch_pattern: lightly left-hatched
    color: "blue"
  DICING:
    layer: [65, 0]
    layer_in_name: true
    hatch_pattern: coarsely dotted
    width: 1
    color: "#cc0000"
  DRC_EXCLUDE:
    layer: [67, 0]
    layer_in_name: true
    hatch_pattern: hollow
    visible: false
    width: 2
    color: "black"
  FLOORPLAN:
    layer: [64, 0]
    layer_in_name: true
    hatch_pattern: hollow
    color: "black"
  simulation:
    group_members:
      SIM_REGION:
        layer: [100, 0]
        layer_in_name: true
        hatch_pattern: hollow
        color: "black"
      MONITOR:
        layer: [101, 0]
        layer_in_name: true
        hatch_pattern: hollow
        color: "blue"
      SOURCE:
        layer: [110, 0]
        layer_in_name: true
        hatch_pattern: hollow
        color: "red"
  Lumerical:
    layer: [733, 0]
    hatch_pattern: hollow
    width: 3
    color: "#800057"
  DevRec:
    layer: [68, 0]
    hatch_pattern: hollow
    visible: false
    transparent: true
    width: 1
    color: "#004080"
  PinRec:
    layer: [1, 10]
    hatch_pattern: hollow
    color: "#404040"
  FbrTgt:
    layer: [81, 0]
    hatch_pattern: lightly right-hatched
    width: 2
    color: "#004080"
  Text:
    layer: [66, 0]
    hatch_pattern: hollow
    width: 1
    color: "blue"
  Errors:
    layer: [69, 0]
    hatch_pattern: hollow
    width: 1
    color: "blue"
  PinRecM:
    layer: [1, 11]
    hatch_pattern: hollow
    width: 1
    color: "#004080"
  XSECTION:
    group_members:
      XS_BOX:
        layer: [300, 0]
        layer_in_name: true
        width: 1
        color: "#f3ff80"
      XS_SI:
        layer: [301, 0]
        layer_in_name: true
        width: 1
        color: "black"
      XS_SIN:
        layer: [319, 0]
        layer_in_name: true
        width: 1
        color: "black"
      XS_N:
        layer: [320, 0]
        layer_in_name: true
        width: 1
        color: "#008ca5"
      XS_NPP:
        layer: [321, 0]
        layer_in_name: true
        width: 1
        color: "#004ca5"
      XS_P:
        layer: [330, 0]
        layer_in_name: true
        width: 1
        color: "#00f233"
      XS_PDPP:
        layer: [327, 0]
        layer_in_name: true
        width: 1
        color: "#00f233"
      XS_PPP:
        layer: [331, 0]
        layer_in_name: true
        width: 1
        color: "#00b233"
      XS_SI_SLAB:
        layer: [313, 0]
        layer_in_name: true
        width: 1
        color: "#80a8ff"
      XS_OVERLAY:
        layer: [311, 0]
        layer_in_name: true
        width: 1
        color: "blue"
      XS_OX_SI:
        layer: [302, 0]
        layer_in_name: true
        width: 1
        color: "#f3ff80"
      XS_GE:
        layer: [315, 0]
        layer_in_name: true
        width: 1
        color: "#004ca5"
      XS_VIAC:
        layer: [303, 0]
        layer_in_name: true
        width: 1
        color: "grey"
      XS_M1:
        layer: [304, 0]
        layer_in_name: true
        width: 1
        color: "green"
      XS_OXIDE_M1:
        layer: [305, 0]
        layer_in_name: true
        width: 1
        color: "#f3ff80"
      XS_MH:
        layer: [306, 0]
        layer_in_name: true
        width: 1
        color: "green"
      XS_OXIDE_M2:
        layer: [307, 0]
        layer_in_name: true
        width: 1
        color: "#f3ff80"
      XS_OXIDE_MH:
        layer: [317, 0]
        layer_in_name: true
        width: 1
        color: "#f3ff80"
      XS_OXIDE_ML:
        layer: [309, 0]
        layer_in_name: true
        width: 1
        color: "#f3ff80"
      XS_VIA1:
        layer: [308, 0]
        layer_in_name: true
        width: 1
        color: "grey"
      XS_M2:
        layer: [399, 0]
        layer_in_name: true
        width: 1
        color: "#805000"
      XS_OXIDE_M3:
        layer: [311, 0]
        layer_in_name: true
        width: 1
        color: "#f3ff80"
      XS_VIA2:
        layer: [310, 0]
        layer_in_name: true
        width: 1
        color: "grey"
      XS_SIN2:
        layer: [305, 0]
        layer_in_name: true
        width: 1
        color: "#805000"
  DRC_MARKER:
    layer: [205, 0]
    layer_in_name: true
    transparent: true
    width: 3
    color: "red"
  ERROR_MARKER:
    layer: [207, 0]
    layer_in_name: true
    transparent: true
    width: 3
    color: "red"
  NOTILE_M1:
    layer: [71, 0]
    layer_in_name: true
    hatch_pattern: coarsely dotted
    visible: false
    color: "grey"
  NOTILE_M2:
    layer: [72, 0]
    layer_in_name: true
    hatch_pattern: coarsely dotted
    visible: false
    color: "grey"
  NOTILE_M3:
    layer: [73, 0]
    layer_in_name: true
    hatch_pattern: coarsely dotted
    visible: false
    color: "#606060"
  SHOW_PORTS:
    layer: [1, 12]
    layer_in_name: true
    hatch_pattern: lightly left-hatched
    color: "#ff80a8"

Once you modify the YAML file you can easily write it to klayout.

[10]:
help(gf.generic_tech.write_lyp)
Help on function write_lyp in module gdsfactory.generic_tech:

write_lyp() -> 'None'
    Write from YAML to Klayout lyp file

[11]:
c = LAYER_VIEWS.preview_layerset()
c
layerset_f12a4bf9: uid f12a4bf9, ports [], references ['rectangle_1', 'text_1', 'rectangle_2', 'text_2', 'rectangle_3', 'text_3', 'rectangle_4', 'text_4', 'rectangle_5', 'text_5', 'rectangle_6', 'text_6', 'rectangle_7', 'text_7', 'rectangle_8', 'text_8', 'rectangle_9', 'text_9', 'rectangle_10', 'text_10', 'rectangle_11', 'text_11', 'rectangle_12', 'text_12', 'rectangle_13', 'text_13', 'rectangle_14', 'text_14', 'rectangle_15', 'text_15', 'rectangle_16', 'text_16', 'rectangle_17', 'text_17', 'rectangle_18', 'text_18', 'rectangle_19', 'text_19', 'rectangle_20', 'text_20', 'rectangle_21', 'text_21', 'rectangle_22', 'text_22', 'rectangle_23', 'text_23', 'rectangle_24', 'text_24', 'rectangle_25', 'text_25', 'rectangle_26', 'text_26', 'rectangle_27', 'text_27', 'rectangle_28', 'text_28', 'rectangle_29', 'text_29', 'rectangle_30', 'text_30', 'rectangle_31', 'text_31', 'rectangle_32', 'text_32', 'rectangle_33', 'text_33', 'rectangle_34', 'text_34', 'rectangle_35', 'text_35', 'rectangle_36', 'text_36', 'rectangle_37', 'text_37', 'rectangle_38', 'text_38', 'rectangle_39', 'text_39', 'rectangle_40', 'text_40', 'rectangle_41', 'text_41', 'rectangle_42', 'text_42', 'rectangle_43', 'text_43', 'rectangle_44', 'text_44', 'rectangle_45', 'text_45', 'rectangle_46', 'text_46', 'rectangle_47', 'text_47', 'rectangle_48', 'text_48', 'rectangle_49', 'text_49', 'rectangle_50', 'text_50', 'rectangle_51', 'text_51', 'rectangle_52', 'text_52', 'rectangle_53', 'text_53', 'rectangle_54', 'text_54', 'rectangle_55', 'text_55', 'rectangle_56', 'text_56', 'rectangle_57', 'text_57', 'rectangle_58', 'text_58', 'rectangle_59', 'text_59', 'rectangle_60', 'text_60', 'rectangle_61', 'text_61', 'rectangle_62', 'text_62', 'rectangle_63', 'text_63', 'rectangle_64', 'text_64', 'rectangle_65', 'text_65', 'rectangle_66', 'text_66', 'rectangle_67', 'text_67', 'rectangle_68', 'text_68', 'rectangle_69', 'text_69', 'rectangle_70', 'text_70', 'rectangle_71', 'text_71', 'rectangle_72', 'text_72', 'rectangle_73', 'text_73', 'rectangle_74', 'text_74', 'rectangle_75', 'text_75', 'rectangle_76', 'text_76', 'rectangle_77', 'text_77', 'rectangle_78', 'text_78', 'rectangle_79', 'text_79', 'rectangle_80', 'text_80', 'rectangle_81', 'text_81', 'rectangle_82', 'text_82'], 0 polygons

By default the generic PDK has some layers that are not visible and therefore are not shown.

[12]:
c_wg_clad = c.extract(layers=gf.LAYER.WGCLAD)
c_wg_clad
/home/runner/work/gdsfactory/gdsfactory/gdsfactory/component.py:1684: UserWarning: Component 'Unnamed_36e7280b' contains 1 Unnamed cells
  warnings.warn(
Unnamed_36e7280b: uid 36e7280b, ports [], references [], 13 polygons
[13]:
LAYER_VIEWS.layer_views["WGCLAD"]
LayerView(
    name='WGCLAD',
    info=None,
    layer=(111, 0),
    layer_in_name=True,
    frame_color=Color('silver', rgb=(192, 192, 192)),
    fill_color=Color('silver', rgb=(192, 192, 192)),
    frame_brightness=0,
    fill_brightness=0,
    hatch_pattern='coarsely dotted',
    line_style=None,
    valid=True,
    visible=False,
    transparent=False,
    width=1,
    marked=False,
    xfill=False,
    animation=0,
    group_members={}
)
[14]:
LAYER_VIEWS.layer_views["WGCLAD"].visible
False

You can make it visible

[15]:
LAYER_VIEWS.layer_views["WGCLAD"].visible = True
[16]:
LAYER_VIEWS.layer_views["WGCLAD"].visible
True
[17]:
c_wg_clad = c.extract(layers=gf.LAYER.WGCLAD)
c_wg_clad
/home/runner/work/gdsfactory/gdsfactory/gdsfactory/component.py:1684: UserWarning: Component 'Unnamed_df1cbc3e' contains 1 Unnamed cells
  warnings.warn(
Unnamed_df1cbc3e: uid df1cbc3e, ports [], references [], 13 polygons

LayerStack#

Each layer also includes the information of thickness and position of each layer.

This LayerStack can be used for creating a 3D model with Component.to_3d or running Simulations.

A GDS has different layers to describe the different fabrication process steps. And each grown layer needs thickness information and z-position in the stack.

layer stack

Lets define the layer stack for the generic layers in the generic_technology.

[18]:
nm = 1e-3


def get_layer_stack(
    thickness_wg: float = 220 * nm,
    thickness_slab_deep_etch: float = 90 * nm,
    thickness_clad: float = 3.0,
    thickness_nitride: float = 350 * nm,
    thickness_ge: float = 500 * nm,
    gap_silicon_to_nitride: float = 100 * nm,
    zmin_heater: float = 1.1,
    zmin_metal1: float = 1.1,
    thickness_metal1: float = 700 * nm,
    zmin_metal2: float = 2.3,
    thickness_metal2: float = 700 * nm,
    zmin_metal3: float = 3.2,
    thickness_metal3: float = 2000 * nm,
    substrate_thickness: float = 10.0,
    box_thickness: float = 3.0,
    undercut_thickness: float = 5.0,
) -> LayerStack:
    """Returns generic LayerStack.

    based on paper https://www.degruyter.com/document/doi/10.1515/nanoph-2013-0034/html

    Args:
        thickness_wg: waveguide thickness in um.
        thickness_slab_deep_etch: for deep etched slab.
        thickness_clad: cladding thickness in um.
        thickness_nitride: nitride thickness in um.
        thickness_ge: germanium thickness.
        gap_silicon_to_nitride: distance from silicon to nitride in um.
        zmin_heater: TiN heater.
        zmin_metal1: metal1.
        thickness_metal1: metal1 thickness.
        zmin_metal2: metal2.
        thickness_metal2: metal2 thickness.
        zmin_metal3: metal3.
        thickness_metal3: metal3 thickness.
        substrate_thickness: substrate thickness in um.
        box_thickness: bottom oxide thickness in um.
        undercut_thickness: thickness of the silicon undercut.
    """

    class GenericLayerStack(LayerStack):
        substrate = LayerLevel(
            layer=LAYER.WAFER,
            thickness=substrate_thickness,
            zmin=-substrate_thickness - box_thickness,
            material="si",
            info={"mesh_order": 99},
        )
        box = LayerLevel(
            layer=LAYER.WAFER,
            thickness=box_thickness,
            zmin=-box_thickness,
            material="sio2",
            info={"mesh_order": 99},
        )
        core = LayerLevel(
            layer=LAYER.WG,
            thickness=thickness_wg,
            zmin=0.0,
            material="si",
            info={"mesh_order": 1},
            sidewall_angle=10,
            width_to_z=0.5,
        )
        clad = LayerLevel(
            # layer=LAYER.WGCLAD,
            layer=LAYER.WAFER,
            zmin=0.0,
            material="sio2",
            thickness=thickness_clad,
            info={"mesh_order": 10},
        )
        slab150 = LayerLevel(
            layer=LAYER.SLAB150,
            thickness=150e-3,
            zmin=0,
            material="si",
            info={"mesh_order": 3},
        )
        slab90 = LayerLevel(
            layer=LAYER.SLAB90,
            thickness=thickness_slab_deep_etch,
            zmin=0.0,
            material="si",
            info={"mesh_order": 2},
        )
        nitride = LayerLevel(
            layer=LAYER.WGN,
            thickness=thickness_nitride,
            zmin=thickness_wg + gap_silicon_to_nitride,
            material="sin",
            info={"mesh_order": 2},
        )
        ge = LayerLevel(
            layer=LAYER.GE,
            thickness=thickness_ge,
            zmin=thickness_wg,
            material="ge",
            info={"mesh_order": 1},
        )
        undercut = LayerLevel(
            layer=LAYER.UNDERCUT,
            thickness=-undercut_thickness,
            zmin=-box_thickness,
            material="air",
            z_to_bias=[
                [0, 0.3, 0.6, 0.8, 0.9, 1],
                [-0, -0.5, -1, -1.5, -2, -2.5],
            ],
            info={"mesh_order": 1},
        )
        via_contact = LayerLevel(
            layer=LAYER.VIAC,
            thickness=zmin_metal1 - thickness_slab_deep_etch,
            zmin=thickness_slab_deep_etch,
            material="Aluminum",
            info={"mesh_order": 1},
            sidewall_angle=-10,
            width_to_z=0,
        )
        metal1 = LayerLevel(
            layer=LAYER.M1,
            thickness=thickness_metal1,
            zmin=zmin_metal1,
            material="Aluminum",
            info={"mesh_order": 2},
        )
        heater = LayerLevel(
            layer=LAYER.HEATER,
            thickness=750e-3,
            zmin=zmin_heater,
            material="TiN",
            info={"mesh_order": 1},
        )
        via1 = LayerLevel(
            layer=LAYER.VIA1,
            thickness=zmin_metal2 - (zmin_metal1 + thickness_metal1),
            zmin=zmin_metal1 + thickness_metal1,
            material="Aluminum",
            info={"mesh_order": 2},
        )
        metal2 = LayerLevel(
            layer=LAYER.M2,
            thickness=thickness_metal2,
            zmin=zmin_metal2,
            material="Aluminum",
            info={"mesh_order": 2},
        )
        via2 = LayerLevel(
            layer=LAYER.VIA2,
            thickness=zmin_metal3 - (zmin_metal2 + thickness_metal2),
            zmin=zmin_metal2 + thickness_metal2,
            material="Aluminum",
            info={"mesh_order": 1},
        )
        metal3 = LayerLevel(
            layer=LAYER.M3,
            thickness=thickness_metal3,
            zmin=zmin_metal3,
            material="Aluminum",
            info={"mesh_order": 2},
        )

    return GenericLayerStack()


layer_stack220 = get_layer_stack(thickness_wg=0.220)
[19]:
import gdsfactory as gf
c = gf.components.straight_heater_doped_rib(length=100)
c
straight_heater_doped_r_be2f5e0f: uid 45ab7276, ports ['o1', 'o2', 'top_e1', 'top_e2', 'top_e3', 'top_e4', 'bot_e1', 'bot_e2', 'bot_e3', 'bot_e4'], references ['straight_1', 'taper_cross_section_1', 'taper_cross_section_2', 'via_stack_1', 'via_stack_2', 'via_stack_3', 'via_stack_4', 'via_stack_5', 'via_stack_6', 'via_stack_7', 'via_stack_8', 'via_stack_9', 'via_stack_10', 'via_stack_11', 'via_stack_12', 'via_stack_13', 'via_stack_14', 'via_stack_15', 'via_stack_16', 'via_stack_17', 'via_stack_18'], 0 polygons
[20]:
import gdsfactory as gf
c = gf.components.straight_heater_metal(length=40)
c
straight_heater_metal_u_d99b3f2a: uid db924e1d, ports ['o1', 'o2', 'e1', 'e2'], references ['component_sequence_1', 'via_stack_1', 'via_stack_2', 'taper_1', 'taper_2'], 0 polygons
[21]:
scene = c.to_3d(layer_stack=layer_stack220)
scene.show()
[21]:
[22]:
# lets assume we have 0.900 silicon instead of 0.220um, You will see a much thicker waveguide under the metal heater.
layer_stack9000 = get_layer_stack(thickness_wg=0.9)
scene = c.to_3d(layer_stack=layer_stack9000)
scene.show()
[22]:

3D rendering#

To render components in 3D you will need to define two things:

  1. LayerStack: for each layer contains thickness of each material and z position

  2. LayerViews: for each layer contains view (color, pattern, opacity). You can load it with gf.technology.LayerView.load_lyp()

[23]:
heater = gf.components.straight_heater_metal(length=50)
heater
straight_heater_metal_u_d92d12b4: uid 34618ea9, ports ['o1', 'o2', 'e1', 'e2'], references ['component_sequence_1', 'via_stack_1', 'via_stack_2', 'taper_1', 'taper_2'], 0 polygons
[24]:
scene = heater.to_3d()
scene.show()
[24]:

Klayout 2.5D view#

From the LayerStack you can generate the KLayout 2.5D view script.

[25]:
LAYER_STACK.get_klayout_3d_script()
z(input(99999, 0), zstart: -13.0, zstop: -3.0, name: 'substrate: si 99999/0')
z(input(99999, 0), zstart: -3.0, zstop: 0.0, name: 'box: sio2 99999/0')
z(input(1, 0), zstart: 0.0, zstop: 0.22, name: 'core: si 1/0')
z(input(99999, 0), zstart: 0.0, zstop: 3.0, name: 'clad: sio2 99999/0')
z(input(2, 0), zstart: 0.0, zstop: 0.15, name: 'slab150: si 2/0')
z(input(3, 0), zstart: 0.0, zstop: 0.09, name: 'slab90: si 3/0')
z(input(34, 0), zstart: 0.32, zstop: 0.67, name: 'nitride: sin 34/0')
z(input(5, 0), zstart: 0.22, zstop: 0.72, name: 'ge: ge 5/0')
z(input(6, 0), zstart: -3.0, zstop: -8.0, name: 'undercut: air 6/0')
z(input(40, 0), zstart: 0.09, zstop: 1.1, name: 'via_contact: Aluminum 40/0')
z(input(41, 0), zstart: 1.1, zstop: 1.8, name: 'metal1: Aluminum 41/0')
z(input(47, 0), zstart: 1.1, zstop: 1.85, name: 'heater: TiN 47/0')
z(input(44, 0), zstart: 1.8, zstop: 2.3, name: 'via1: Aluminum 44/0')
z(input(45, 0), zstart: 2.3, zstop: 3.0, name: 'metal2: Aluminum 45/0')
z(input(43, 0), zstart: 3.0, zstop: 3.2, name: 'via2: Aluminum 43/0')
z(input(49, 0), zstart: 3.2, zstop: 5.2, name: 'metal3: Aluminum 49/0')
"z(input(99999, 0), zstart: -13.0, zstop: -3.0, name: 'substrate: si 99999/0')\nz(input(99999, 0), zstart: -3.0, zstop: 0.0, name: 'box: sio2 99999/0')\nz(input(1, 0), zstart: 0.0, zstop: 0.22, name: 'core: si 1/0')\nz(input(99999, 0), zstart: 0.0, zstop: 3.0, name: 'clad: sio2 99999/0')\nz(input(2, 0), zstart: 0.0, zstop: 0.15, name: 'slab150: si 2/0')\nz(input(3, 0), zstart: 0.0, zstop: 0.09, name: 'slab90: si 3/0')\nz(input(34, 0), zstart: 0.32, zstop: 0.67, name: 'nitride: sin 34/0')\nz(input(5, 0), zstart: 0.22, zstop: 0.72, name: 'ge: ge 5/0')\nz(input(6, 0), zstart: -3.0, zstop: -8.0, name: 'undercut: air 6/0')\nz(input(40, 0), zstart: 0.09, zstop: 1.1, name: 'via_contact: Aluminum 40/0')\nz(input(41, 0), zstart: 1.1, zstop: 1.8, name: 'metal1: Aluminum 41/0')\nz(input(47, 0), zstart: 1.1, zstop: 1.85, name: 'heater: TiN 47/0')\nz(input(44, 0), zstart: 1.8, zstop: 2.3, name: 'via1: Aluminum 44/0')\nz(input(45, 0), zstart: 2.3, zstop: 3.0, name: 'metal2: Aluminum 45/0')\nz(input(43, 0), zstart: 3.0, zstop: 3.2, name: 'via2: Aluminum 43/0')\nz(input(49, 0), zstart: 3.2, zstop: 5.2, name: 'metal3: Aluminum 49/0')\n"

Then you go go Tools → Manage Technologies

klayout

and Paste the script

paste

Klayout cross-section#

You can also install the KLayout cross-section plugin

xsection

This is not integrated with the LayerStack but you can use the script in gdsfactory.generic_tech.get_klayout_pyxs and customize it for your technology.

[26]:
nm = 1e-3
if __name__ == "__main__":
    script = get_klayout_pyxs(
        t_box=2.0,
        t_slab=110 * nm,
        t_si=220 * nm,
        t_ge=400 * nm,
        t_nitride=400 * nm,
        h_etch1=0.07,
        h_etch2=0.06,
        h_etch3=0.09,
        t_clad=0.6,
        t_m1=0.5,
        t_m2=0.5,
        t_m3=2.0,
        gap_m1_m2=0.6,
        gap_m2_m3=0.3,
        t_heater=0.1,
        gap_oxide_nitride=0.82,
        t_m1_oxide=0.6,
        t_m2_oxide=2.0,
        t_m3_oxide=0.5,
        layer_wg=LAYER.WG,
        layer_fc=LAYER.SLAB150,
        layer_rib=LAYER.SLAB90,
        layer_n=LAYER.N,
        layer_np=LAYER.NP,
        layer_npp=LAYER.NPP,
        layer_p=LAYER.P,
        layer_pp=LAYER.PP,
        layer_ppp=LAYER.PPP,
        layer_PDPP=LAYER.GEP,
        layer_nitride=LAYER.WGN,
        layer_Ge=LAYER.GE,
        layer_GePPp=LAYER.GEP,
        layer_GeNPP=LAYER.GEN,
        layer_viac=LAYER.VIAC,
        layer_viac_slot=LAYER.VIAC,
        layer_m1=LAYER.M1,
        layer_mh=LAYER.HEATER,
        layer_via1=LAYER.VIA1,
        layer_m2=LAYER.M2,
        layer_via2=LAYER.VIA2,
        layer_m3=LAYER.M3,
        layer_open=LAYER.PADOPEN,
    )

    # script_path = pathlib.Path(__file__).parent.absolute() / "xsection_planarized.pyxs"
    # script_path.write_text(script)
    print(script)


t_box=2.0
t_slab=0.11
t_si=0.22
t_ge=0.4
t_nitride=0.4
h_etch1=0.07
h_etch2=0.06
h_etch3=0.09
t_clad=0.6
t_m1=0.5
t_m2=0.5
t_m3=2.0
t_heater=0.1
gap_m1_m2=0.6
gap_m2_m3=0.3
gap_oxide_nitride=0.82
t_m1_oxide=0.6
t_m2_oxide=2.0
t_m3_oxide=0.5

l_wg = layer('1/0')
l_fc = layer('2/0')
l_rib = layer('3/0')

l_n = layer('20/0')
l_np = layer('22/0')
l_npp = layer('24/0')
l_p = layer('21/0')
l_pp = layer('23/0')
l_ppp = layer('25/0')
l_PDPP = layer('27/0')
l_bottom_implant = l_PDPP

l_nitride = layer('34/0')
l_Ge = layer('5/0')
l_GePPp = layer('27/0')
l_GeNPP = layer('26/0')

l_viac = layer('40/0')
l_viac_slot = layer('40/0')
l_m1 = layer('41/0')
l_mh = layer('47/0')
l_via1 = layer('44/0')
l_m2 = layer('45/0')
l_via2 = layer('43/0')
l_m3 = layer('49/0')
l_open = layer('46/0')

l_top_implant = l_GePPp.or_(l_GeNPP)
l_viac = l_viac.or_(l_viac_slot)

# Declare the basic accuracy used to remove artifacts for example: delta(5 * dbu)
delta(dbu)
depth(12.0)
height(12.0)

################ front-end

l_wg_etch1 = l_wg.inverted()  # protects ridge
l_wg_etch2 = (
    l_fc.or_(l_wg)
).inverted()  # protects ridge and grating couplers from the etch down to the slab (forms rib straights)
l_wg_etch3 = (
    l_rib.or_(l_fc).or_(l_wg)
).inverted()  # protects ridge, grating couplers and rib straights from the final etch to form strip straights


################ back-end
substrate = bulk
box = deposit(t_box)
si = deposit(t_si)

################ silicon etch to for the passives
mask(l_wg_etch1).etch(
    h_etch1, 0.0, mode="round", into=[si]
)  # 70nm etch for GC, rib and strip
mask(l_wg_etch2).etch(
    h_etch2, 0.0, mode="round", into=[si]
)  # 60nm etch after 70nm = 130nm etch (90nm slab)
mask(l_wg_etch3).etch(
    h_etch3, 0.0, mode="round", into=[si]
)  # etches the remaining 90nm slab for strip straights

output("300/0", box)
output("301/0", si)

############### doping
mask(l_bottom_implant).etch(t_si, 0.0, mode="round", into=[si])
bottom_implant = mask(l_bottom_implant).grow(t_si, 0.0, mode="round")

mask(l_n).etch(t_slab, 0.0, mode="round", into=[si])
n = mask(l_n).grow(t_slab, 0.0, mode="round")

mask(l_p).etch(t_slab, 0.0, mode="round", into=[si])
p = mask(l_p).grow(t_slab, 0.0, mode="round")

mask(l_np).etch(t_slab, 0.0, mode="round", into=[n, p, si, bottom_implant])
np = mask(l_np).grow(t_slab, 0.0, mode="round")

mask(l_pp).etch(t_slab, 0.0, mode="round", into=[n, p, si, bottom_implant])
pp = mask(l_pp).grow(t_slab, 0.0, mode="round")

mask(l_npp).etch(t_slab, 0.0, mode="round", into=[n, p, np, pp, si, bottom_implant])
npp = mask(l_npp).grow(t_slab, 0.0, mode="round")

mask(l_ppp).etch(t_slab, 0.0, mode="round", into=[n, p, np, pp, si, bottom_implant])
ppp = mask(l_ppp).grow(t_slab, 0.0, mode="round")

output("327/0", bottom_implant)
output("330/0", p)
output("320/0", n)
output("321/0", npp)
output("331/0", ppp)

################ Ge
Ge = mask(l_Ge).grow(t_ge, 0, bias=0.0, taper=10)
output("315/0", Ge)

################ Nitride
ox_nitride = deposit(2 * gap_oxide_nitride, 2 * gap_oxide_nitride)
planarize(less=gap_oxide_nitride, into=[ox_nitride])
output("302/0", ox_nitride)

nitride = mask(l_nitride).grow(t_nitride, 0, bias=0.0, taper=10)
output("305/0", nitride)

################# back-end
################# VIAC, M1 and MH
ox_si = deposit(t_clad + t_ge + t_nitride, t_clad + t_ge + t_nitride, mode="round")
planarize(less=t_ge + t_nitride, into=[ox_si])
mask(l_viac).etch(
    t_clad + t_ge + t_nitride + gap_oxide_nitride, taper=4, into=[ox_si, ox_nitride]
)

viac = deposit(2 * t_clad, 2 * t_clad)
planarize(less=2 * t_clad, into=[viac])

mh = deposit(t_heater, t_heater)
mask(l_mh.inverted()).etch(t_heater + t_heater, into=[mh])
m1 = deposit(t_m1, t_m1)
mask(l_m1.inverted()).etch(t_m1 + t_m1, into=[m1])
output("306/0", mh)
output("399/0", m1)

output("302/0", ox_si)
output("303/0", viac)

################# VIA1 and M2
ox_m1 = deposit(2 * t_m1_oxide, 2 * t_m1_oxide, mode="round")
planarize(less=t_m1_oxide, into=[ox_m1])

mask(l_via1).etch(t_m1_oxide + gap_m1_m2, taper=4, into=[ox_m1])
via1 = deposit(t_m2, t_m2)

mask(l_m2.inverted()).etch(t_m2, taper=4, into=[via1])
output("308/0", via1)

ox_m2 = deposit(2 * t_m2_oxide, 2 * t_m2_oxide, mode="round")
planarize(less=t_m2_oxide, into=[ox_m2])
output("309/0", ox_m2)
output("307/0", ox_m1)

################# VIA2 and M3
mask(l_via2).etch(t_m2_oxide + gap_m2_m3, taper=4, into=[ox_m2, ox_m2])
via2 = deposit(t_m3, t_m3)
mask(l_m3.inverted()).etch(t_m3, taper=4, into=[via2])
output("310/0", via2)

################# passivation and ML Open
ox_m3 = deposit(t_m3_oxide, t_m3_oxide, mode="round")
mask(l_open).etch(t_m3_oxide + t_m3_oxide, into=[ox_m3], taper=5)
output("311/0", ox_m3)

xsection generic